<?php

namespace p5\http;

use Illuminate\Support\Facades\Config;

class C5AuthBean
{
    private $debugOn = false;
    private $logs = [];
    private $maxOffsetTimeMills = 600000;

    public function encrypt($params, $remote_user_id, $salt)
    {
        $params["remote_user_id"] = $remote_user_id;
        $params["salt"] = $salt;
        ksort($params);
        $string = "" . $salt;
        foreach ($params as $key => $value) {
            if ($key == "remote_verify_code" || $key == "salt" || $key == "XDEBUG_SESSION_START") {
                continue;
            }
            if (empty($key)) {
                continue;
            }
            $string .= $key . $value;
        }
        $string .= $salt;
        $this->debug("加密前字符串：" . $string);
        $verifyCode = md5($string);
        $params["remote_verify_code"] = $verifyCode;
//        if (array_key_exists("salt", $params)) {
//            unset($params["salt"]);
//        }
//        return $params;
        return $verifyCode;
    }

    /**
     * @param \Illuminate\Http\Request $request
     * @return mixed
     */
    public function verify($request)
    {
        $remote_user_id = self::find($request, "remote_user_id");
        if (empty($remote_user_id)) {
            $this->debug("找不到 remote_user_id ");
            return false;
        }

        $salt = "";
        $authUsers = Config::get("c5auth.auth_users");
        if (!empty($authUsers)) {
            if (!array_key_exists($remote_user_id, $authUsers)) {
                $this->debug("无效的 remote_user_id : $remote_user_id ");
                return false;
            }
            $salt = $authUsers[$remote_user_id];
        } else {
            $accessUserId = env("C5_ACCESS_USER_ID");
            if (!empty($accessUserId)) {
                if ($accessUserId != $remote_user_id) {
                    $this->debug("无效的 remote_user_id : $remote_user_id ");
                    return false;
                }
                $salt = env("C5_ACCESS_SALT", "0tong.123");
            }
        }

        // ::debug("find salt : [$salt] ");
        $version = $request->header("c5_auth_version");
        if (empty($version)) {
            $params = $request->all();
            $this->killFileParams($params, $request);
            return self::do_verify($params, $remote_user_id, $salt);
        } else {
            $params = [];
            $params["c5_auth_version"] = self::find($request, "c5_auth_version");
            $params["remote_user_id"] = self::find($request, "remote_user_id");
            $params["timestamp"] = self::find($request, "timestamp");
            $params["random_string"] = self::find($request, "random_string");
            $params["remote_verify_code"] = self::find($request, "remote_verify_code");
            return self::do_verify($params, $remote_user_id, $salt);
        }
    }

    public function do_verify($params, $remote_user_id, $salt)
    {
        if (empty($params)) {
            $this->debug("no params ");
            return false;
        }
        if (!array_key_exists("remote_user_id", $params)) {
            $this->debug("no remote_user_id");
            return false;
        }
        if (!array_key_exists("timestamp", $params) || !array_key_exists("remote_verify_code", $params)) {
            $this->debug("need timestamp and remote_verify_code");
            return false;
        }
        // 检查时长
        $current_time = self::get_milli_time();
        if (abs($current_time * 1 - $params["timestamp"]) > $this->maxOffsetTimeMills) {
            $this->debug("timestamp 误差超过 " . $this->maxOffsetTimeMills);
            return false;
        }
        $code = $params["remote_verify_code"];
        $this->debug("接收到的 remote_verify_code = {$code}");
        $md5 = self::encrypt($params, $remote_user_id, $salt);
        $this->debug("本机计算的 md5 = {$md5}");
        if ($md5 != $code) {
            return false;
        }
        return true;
    }

    /**
     * @param \Illuminate\Http\Request $request
     * @param $params
     */
    public function killFileParams(&$params, $request)
    {
        $files = $request->allFiles();
        foreach ($files as $name => $value) {
            if (array_key_exists($name, $params)) {
                unset($params[$name]);
            }
        }

    }


    public function get_milli_time()
    {
        $time_test = microtime();
        list($ten_thousand, $sec) = explode(" ", $time_test);
        $time = ((float)$ten_thousand + (float)$sec);
        return round($time * 1000);
    }

    /**
     * @param \Illuminate\Http\Request $request
     * @return mixed
     */
    public function find($request, $name)
    {
        $value = $request->header($name);
        if (empty($value)) {
            $value = $request->get($name);
        }
        return $value;
    }

    public function getStringLogs()
    {
        return implode("\r\n", $this->logs);
    }

    private function debug($string)
    {
        global $logger;
        array_push($this->logs, $string);
        if ($this->debugOn === false) {
            return;
        }
        if (isset($logger)) {
            $logger->debug($string);
        } else {
            echo $string;
        }
    }

    /**
     * @return bool
     */
    public function isDebugOn()
    {
        return $this->debugOn;
    }

    /**
     * @param bool $debugOn
     */
    public function setDebugOn($debugOn)
    {
        $this->debugOn = $debugOn;
    }

    /**
     * @return array
     */
    public function getLogs()
    {
        return $this->logs;
    }

    /**
     * @param array $logs
     */
    public function setLogs($logs)
    {
        $this->logs = $logs;
    }

    public function clearLogs()
    {
        $this->logs = [];
    }

    /**
     * @return int
     */
    public function getMaxOffsetTimeMills()
    {
        return $this->maxOffsetTimeMills;
    }

    /**
     * @param int $maxOffsetTimeMills
     */
    public function setMaxOffsetTimeMills($maxOffsetTimeMills)
    {
        $this->maxOffsetTimeMills = $maxOffsetTimeMills;
    }


}
